package cn.mjc.game.sudoku;

/**
 * the abstract class for {@link NPalace} interface and provide the utility
 * method for resolving.
 * 
 * @author EricMa
 * 
 */
public abstract class AbstractNResolver implements NResolver {
	protected NPalace npalace;

	public AbstractNResolver(NPalace npalace) {
		this.npalace = npalace;
	}

	/**
	 * get the values in a new one-dimensional array that the specified position
	 * of data can be put,if there are no any value can be set to this
	 * position,the method will return null.
	 * <P/>
	 * 
	 * for examples,in a default NPalace the initialize data in array as
	 * following:<br/>
	 * 
	 * <pre>
	 * 1   9   0   6   0   0   5   0   8
	 * 0   0   6   1   5   0   3   7   0
	 * 3   5   0   4   0   0   0   2   6
	 * 0   0   2   0   0   6   0   0   5
	 * 0   0   0   0   9   4   6   0   0
	 * 0   0   9   0   0   7   0   3   2
	 * 7   2   0   8   3   0   0   0   0
	 * 0   0   0   0   0   1   0   5   0
	 * 9   6   5   0   0   2   0   0   0
	 * </pre>
	 * 
	 * zero value in the array means blank and should be put value from user.
	 * <P/>
	 * The position with x=0 and y=2 is a blank,the previous value is 9 and the
	 * next value is 6 in the same row.According to the rule of sudoku, in the
	 * row this blank can be set the value is:2,3,4,7;and in the column this
	 * blank can be set the value is:1,3,4,7,8;in the small palace this blank
	 * can be set the value is:2,4,7,8.So the intersection of three is: 4,7,and
	 * this is the return from this method.
	 * 
	 * @param data
	 * @param x
	 * @param y
	 * @return
	 */
	public int[] getValueRange(int[][] data, int x, int y) {
		int[] tmp = new int[npalace.getCellSize()];
		for (int i = 0; i < tmp.length; i++)
			tmp[i] = i + 1;
		int size = tmp.length;
		// column check
		for (int _x = x, _y = 0; _y < npalace.getCellSize(); _y++) {
			if (_y == y)
				continue;
			int value = data[_x][_y];
			if (value <= 0)
				continue;
			if (tmp[value - 1] > 0)
				size--;
			tmp[value - 1] = 0;
		}
		// row check
		for (int _x = 0, _y = y; _x < npalace.getCellSize(); _x++) {
			if (_x == x)
				continue;
			int value = data[_x][_y];
			if (value <= 0)
				continue;
			if (tmp[value - 1] > 0)
				size--;
			tmp[value - 1] = 0;
		}
		// small palace check
		int nsize = npalace.getNSize();
		int startX = x / nsize * nsize, startY = y / nsize * nsize;
		int[][] palaceValues = new int[nsize][nsize];
		for (int _x = startX; _x < startX + nsize; _x++) {
			for (int _y = startY; _y < startY + nsize; _y++) {
				if (_x == x && _y == y)
					continue;
				palaceValues[_x - startX][_y - startY] = data[_x][_y];
			}
		}
		for (int _x = 0; _x < nsize; _x++) {
			for (int _y = 0; _y < nsize; _y++) {
				int value = palaceValues[_x][_y];
				if (value <= 0)
					continue;
				if (tmp[value - 1] > 0)
					size--;
				tmp[value - 1] = 0;
			}
		}
		// fetch positive value in the temporary array
		if (size <= 0)
			return null;
		int[] result = new int[size];
		for (int i = 0, j = 0; i < tmp.length; i++) {
			if (tmp[i] == 0)
				continue;
			result[j++] = tmp[i];
		}
		return result;
	}

}
